#include "stdafx.h"
#include "GraphicsBuffer.h"

#include "VertexBuffer.h"
#include "../mesh/Mesh.h"
#include "../mesh/MeshPart.h"
#include "../mesh/VertexStream.h"

namespace WindGE
{
	GraphicsBuffer::GraphicsBuffer()
		: render_device_(nullptr)
		, ib_(nullptr)
	{
	}

	GraphicsBuffer::~GraphicsBuffer()
	{
	}

	bool GraphicsBuffer::init(RenderDevicePtr renderDevice, std::initializer_list<bool> isDynamicVec, 
							  bool hasIndex /* = true */, bool indexDynamic /* = false */)
	{
		for (auto iter = isDynamicVec.begin(); iter != isDynamicVec.end(); ++iter)
		{
			VertexBufferPtr vb = std::make_shared<VertexBuffer>();
			if (!vb->init(renderDevice, evb_vertex, *iter)) return false;
			vb_list_.push_back(vb);
		}

		if (hasIndex)
		{
			ib_ = std::make_shared<VertexBuffer>();
			if (!ib_->init(renderDevice, evb_index, indexDynamic)) return false;
		}

		return true;
	}

	bool GraphicsBuffer::build(MeshPartPtr meshPart)
	{
		vs_names_.clear();

		buff_info_ = meshPart->part_info();

		int i = 0;
		meshPart->visit_stream_mapping([&i, this](VertexStreamPair vsPair)
		{
			VertexStreamPtr vstream = vsPair.second;
			if (!vstream->is_index())
			{
				vs_names_.insert({ vsPair.first, i });
				vb_list_[i]->build(vstream->buffer(), vstream->stride(), vstream->count());
				i++;
			}
			else
			{
				ib_->build(vstream->buffer(), vstream->stride(), vstream->count());
			}
		});

		return true;
	}

	bool GraphicsBuffer::build(const MeshPart& meshPart)
	{
		vs_names_.clear();
		
		buff_info_ = meshPart.part_info();

		int i = 0;
		meshPart.visit_stream_mapping([&i, this](VertexStreamPair vsPair)
		{
			VertexStreamPtr vstream = vsPair.second;
			if (!vstream->is_index())
			{
				vs_names_.insert({ vsPair.first, i });
				vb_list_[i]->build(vstream->buffer(), vstream->stride(), vstream->count());
				i++;
			}
			else
			{
				ib_->build(vstream->buffer(), vstream->stride(), vstream->count());
			}
		});

		return true;
	}

	void GraphicsBuffer::bind_vertex_buffer(unsigned int slot, unsigned int offset)
	{
		if (slot < 0 || slot >= vb_list_.size()) return;
		vb_list_[slot]->bind_vertex(slot, offset);
	}

	void GraphicsBuffer::bind_vertex_buffer(const std::string& name, unsigned int offset)
	{
		auto iter = vs_names_.find(name);
		if (iter != vs_names_.end())
		{
			vb_list_[iter->second]->bind_vertex(iter->second, offset);
		}
	}

	void GraphicsBuffer::bind_index_buffer(unsigned int offset)
	{
		ib_->bind_index(offset);
	}

	bool GraphicsBuffer::update_vertex_buffer(unsigned int slot, unsigned int size, void* datas)
	{
		if (slot < 0 || slot >= vb_list_.size()) return false;
		void* tempBuff = nullptr;
		if (!vb_list_[slot]->map(&tempBuff, (unsigned int)D3D11_MAP_WRITE_DISCARD)) return false;

		memcpy(tempBuff, datas, size);

		if (!vb_list_[slot]->unmap()) return false;

		return true;
	}

	bool GraphicsBuffer::update_vertex_buffer(const std::string& name, unsigned int size, void* datas)
	{
		auto iter = vs_names_.find(name);
		if (iter != vs_names_.end())
		{
			void* tempBuff = nullptr;
			if (!vb_list_[iter->second]->map(&tempBuff, (unsigned int)D3D11_MAP_WRITE_DISCARD)) return false;

			memcpy(tempBuff, datas, size);

			if (!vb_list_[iter->second]->unmap()) return false;

			return true;
		}
		return false;
	}

	bool GraphicsBuffer::update_index_buffer(unsigned int size, void* datas)
	{
		void* tempBuff = nullptr;
		if (!ib_->map(&tempBuff, (unsigned int)D3D11_MAP_WRITE_DISCARD)) return false;

		memcpy(tempBuff, datas, size);

		if (!ib_->unmap()) return false;

		return true;
	}

}//end namespace WindGE
